package org.mineground.world;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jibble.pircbot.Colors;
import org.mineground.Main;
import org.mineground.PermissionNodes;
import org.mineground.Utilities;
import org.mineground.player.MinegroundPlayer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @file WarpLoader.java (18.02.2012)
 * @author Daniel Koenen
 *
 */
public class WarpLoader {
    private static final Logger ExceptionLogger = LoggerFactory.getLogger(WarpLoader.class);
    
    public static final int INVALID_WARP_ID = -1;
    public static Map<Integer, Warp> warps = new HashMap<Integer, Warp>();

    public static void load() {
	StringBuilder query = new StringBuilder();

	query.append("SELECT ");
	query.append("w.warp_id, ");
	query.append("w.name, ");
	query.append("w.warppass, ");
	query.append("p.login_name, ");
	query.append("w.world, ");
	query.append("w.x, ");
	query.append("w.y, ");
	query.append("w.z, ");
	query.append("w.yaw, ");
	query.append("w.pitch, ");
	query.append("w.is_public ");
	query.append("FROM lvm_warps w ");
	query.append("LEFT JOIN lvm_players p ");
	query.append("ON p.player_id = w.creator_id ");

	try {
	    PreparedStatement statement;
	    statement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement(query.toString());
	    statement.execute();

	    ResultSet result = statement.getResultSet();

	    int id;
	    int x;
	    int y;
	    int z;

	    float yaw;
	    float pitch;

	    long pass;

	    String name;
	    String creator;
	    String world;

	    boolean isPublic;

	    while (result.next()) {
		id = result.getInt(1);
		name = result.getString(2);
		pass = result.getLong(3);
		creator = result.getString(4);
		world = result.getString(5);
		x = result.getInt(6);
		y = result.getInt(7);
		z = result.getInt(8);
		yaw = result.getFloat(9);
		pitch = result.getFloat(10);
		isPublic = result.getBoolean(11);

		try {
		    Warp newWarp = new Warp(id, x, y, z, yaw, pitch, world, creator, name, pass, isPublic);
		    if (!warps.containsKey(id)) {
			warps.put(id, newWarp);
		    }
		} 
                
                catch (Exception e) {
		    // Invalid warp, discard.
		    System.out.println("Exception while loading Wrap ID " + id + ": " + e);
		}
	    }
            
            statement.close();
	}

	catch (Exception exception) {
            ExceptionLogger.error("Exception caught", exception);
	}
    }

    public static int add(MinegroundPlayer player, int x, int y, int z, float yaw, float pitch, String world, String name, long password, boolean isPublic)
	    throws Exception {
	StringBuilder query = new StringBuilder();

	query.append("INSERT INTO lvm_warps (");
	query.append("name, ");
	query.append("warppass, ");
	query.append("creator_id, ");
	query.append("world, ");
	query.append("x, ");
	query.append("y, ");
	query.append("z, ");
	query.append("yaw, ");
	query.append("pitch, ");
	query.append("is_public) ");
	query.append("VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");

	try {
	    PreparedStatement statement;
	    statement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement(query.toString());

	    statement.setString(1, name);
	    statement.setLong(2, password);
	    statement.setInt(3, player.getProfileId());
	    statement.setString(4, world);
	    statement.setInt(5, x);
	    statement.setInt(6, y);
	    statement.setInt(7, z);
	    statement.setFloat(8, yaw);
	    statement.setFloat(9, pitch);
	    statement.setBoolean(10, isPublic);

	    statement.execute();

	    query = new StringBuilder();
	    query.append("SELECT warp_id FROM lvm_warps WHERE name = ?");

	    statement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement(query.toString());
	    statement.setString(1, name);
	    statement.execute();

	    ResultSet result = statement.getResultSet();
	    result.next();

	    int id = result.getInt(1);

	    Warp newWarp = new Warp(id, x, y, z, yaw, pitch, world, player.getPlayer().getName(), name, password, isPublic);

	    if (!warps.containsKey(id)) {
		warps.put(id, newWarp);
	    }

            statement.close();
	    return id;
	}

	catch (Exception exception) {
            ExceptionLogger.error("Exception caught", exception);
	}

	return -1;
    }

    public static boolean remove(Warp warp, Player player) {
	if (!player.getName().equals(warp.getCreator()) && !player.hasPermission(PermissionNodes.PERMISSION_WARP_OVERRIDE)) {
	    player.sendMessage(ChatColor.RED + "* Error: Only warp-creators are allowed to remove their warps.");
	    return true;
	}

	try {
	    PreparedStatement statement;
	    statement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement("DELETE FROM lvm_warps WHERE warp_id = ?");
	    statement.setInt(1, warp.getId());
	    statement.execute();
            statement.close();

	    warps.remove(warp.getId());  
	    return true;
	}

	catch (Exception exception) {
	    ExceptionLogger.error("Exception caught", exception);
	}

	return false;
    }

    public static boolean togglePrivate(Warp warp, Player player, boolean toggle) {
	if (!warp.getCreator().equals(player.getName())) {
	    player.sendMessage(ChatColor.RED + "* Error: Only warp creators are allowed to change warp settings.");
	    return true;
	}

	if (warp.getPublic() == toggle) {
	    player.sendMessage(ChatColor.RED + "* Error: That warp is already " + ((toggle) ? ("public.") : ("private.")));
	    return true;
	}

	try {
	    PreparedStatement statement;
	    statement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement("UPDATE lvm_warps SET is_public = ? WHERE warp_id = ?");
	    statement.setBoolean(1, toggle);
	    statement.setInt(2, warp.getId());
	    statement.execute();

	    warp.setPublic(toggle);

	    StringBuilder inform = new StringBuilder();
	    inform.append(ChatColor.GREEN);
	    inform.append("* Your warp '");
	    inform.append(warp.getName());
	    inform.append("' (ID: ");
	    inform.append(warp.getId());
	    inform.append(") has been made ");
	    inform.append(((toggle) ? ("public.") : ("private.")));
	    player.sendMessage(inform.toString());

	    inform = new StringBuilder();
	    inform.append(Colors.BROWN);
	    inform.append("* ");
	    inform.append(Utilities.fixName(player));
	    inform.append(Colors.BROWN);
	    inform.append(" has made warp '");
	    inform.append(warp.getName());
	    inform.append("' (ID: ");
	    inform.append(warp.getId());
	    inform.append(") ");
	    inform.append(((toggle) ? ("public.") : ("private.")));
	    Main.getInstance().getIRCHandler().sendMessage("@" + Main.getInstance().getConfigHandler().getIrcChannel(), inform.toString());
            statement.close();
	    return true;
	}

	catch (Exception exception) {
            ExceptionLogger.error("Exception caught", exception);
	}

	return false;
    }

    public static boolean setPassword(Warp warp, Player player, String password) {
	if (!warp.getCreator().equals(player.getName())) {
	    player.sendMessage(ChatColor.RED + "* Error: Only warp creators are allowed to change warp settings.");
	    return true;
	}

	if (password.equalsIgnoreCase("remove") && warp.hasPassword()) {
	    password = "";
	}

	if ((password.hashCode() == warp.getPassword()) && warp.hasPassword()) {
	    player.sendMessage(ChatColor.RED + "* Error: You are already using that password.");
	    return true;
	}

	try {
	    PreparedStatement statement;
	    statement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement("UPDATE lvm_warps SET warppass = ? WHERE warp_id = ?");
	    statement.setLong(1, password.hashCode());
	    statement.setInt(2, warp.getId());
	    statement.execute();

	    warp.setPassword(password);

	    player.sendMessage(ChatColor.GREEN + "* Your warp's password has been updated.");
            statement.close();
	    return true;
	}

	catch (Exception exception) {
	    ExceptionLogger.error("Exception caught", exception);
	}

	return false;
    }

    public static boolean setPosition(Warp warp, Player player) {
	if (!warp.getCreator().equals(player.getName())) {
	    player.sendMessage(ChatColor.RED + "* Error: Only warp creators are allowed to change warp settings.");
	    return true;
	}

	Location playerLoc = player.getLocation();

	try {
	    PreparedStatement statement;
	    statement = Main.getInstance().getDatabaseHandler().getConnection().prepareStatement("UPDATE lvm_warps SET world = ?, x = ?, y = ?, z = ?, yaw = ?, pitch = ? WHERE warp_id = ?");
	    statement.setString(1, playerLoc.getWorld().getName());
	    statement.setInt(2, playerLoc.getBlockX());
	    statement.setInt(3, playerLoc.getBlockY());
	    statement.setInt(4, playerLoc.getBlockZ());
	    statement.setFloat(5, playerLoc.getYaw());
	    statement.setFloat(6, playerLoc.getPitch());
	    statement.setInt(7, warp.getId());
	    statement.execute();

	    warp.setWorld(playerLoc.getWorld().getName());
	    warp.setX(playerLoc.getBlockX());
	    warp.setY(playerLoc.getBlockY());
	    warp.setZ(playerLoc.getBlockZ());
	    warp.setYaw(playerLoc.getYaw());
	    warp.setPitch(playerLoc.getPitch());

	    StringBuilder inform = new StringBuilder();
	    inform.append(Colors.BROWN);
	    inform.append("* ");
	    inform.append(Utilities.fixName(player));
	    inform.append(Colors.BROWN);
	    inform.append(" updated the position of warp '");
	    inform.append(warp.getName());
	    inform.append("'.");

	    Main.getInstance().getIRCHandler().sendMessage("@" + Main.getInstance().getConfigHandler().getIrcChannel(), inform.toString());
	    player.sendMessage(ChatColor.GREEN + "* Your warp's position has been updated.");
            statement.close();
	    return true;
	}

	catch (Exception exception) {
	    ExceptionLogger.error("Exception caught", exception);
	}

	return false;
    }

    public static int getWarpID(String name) {
	int id = INVALID_WARP_ID;
	if (Utilities.isNumeric(name)) {
	    id = Integer.parseInt(name);
	}

	else {
	    for (Map.Entry<Integer, Warp> entry : warps.entrySet()) {
		if (entry.getValue().getName().equalsIgnoreCase(name)) {
		    id = entry.getKey();
		    break;
		}
	    }
	}

	return id;
    }

    public static ArrayList<Warp> showWarps(int page) {
	int iterator = 0;
	ArrayList<Warp> alllist = new ArrayList<Warp>();
	ArrayList<Warp> list = new ArrayList<Warp>();

	for (Map.Entry<Integer, Warp> entry : warps.entrySet()) {
	    if (entry.getValue().getPublic()) {
		alllist.add(entry.getValue());
	    }
	}

	for (Warp warp : alllist) {
	    if (iterator >= (page - 1) * 5 && iterator < (page * 5)) {
		list.add(warp);
	    }

	    iterator++;
	}

	return list;
    }

    public static ArrayList<Warp> getPlayerWarps(Player player, int page) {
	int iterator = 0;
	ArrayList<Warp> alllist = new ArrayList<Warp>();
	ArrayList<Warp> list = new ArrayList<Warp>();

	for (Map.Entry<Integer, Warp> entry : warps.entrySet()) {
	    if (entry.getValue().getCreator().equals(player.getName())) {
		alllist.add(entry.getValue());
	    }
	}

	for (Warp warp : alllist) {
	    if (iterator >= (page - 1) * 5 && iterator < (page * 5)) {
		list.add(warp);
	    }

	    iterator++;
	}

	return list;
    }

    public static int getPages() {
	int total = 0;
	int pages = 0;

	for (Map.Entry<Integer, Warp> entry : warps.entrySet()) {
	    if (entry.getValue().getPublic()) {
		total++;
	    }
	}

	while (total >= 5) {
	    pages++;
	    total -= 5;
	}

	if (total > 0) {
	    pages++;
	}

	return pages;
    }

    public static int getPlayerPages(Player player) {
	int total = 0;
	int pages = 0;

	for (Map.Entry<Integer, Warp> entry : warps.entrySet()) {
	    if (entry.getValue().getCreator().equals(player.getName())) {
		total++;
	    }
	}

	while (total >= 5) {
	    pages++;
	    total -= 5;
	}

	if (total > 0) {
	    pages++;
	}

	return pages;
    }

    public static boolean isNameInUse(String name) {
	for (Map.Entry<Integer, Warp> entry : warps.entrySet()) {
	    if (entry.getValue().getName().equalsIgnoreCase(name)) {
		return true;
	    }
	}

	return false;
    }
}
